""" sbak/widget/style.py - sbak.widget.style - Widget styles.
    
    ************************ DEPRECATION NOTICE ***********************
    *   This module is ONLY here for reference. In its present state  *
    *   it cannot be imported due to syntax errors. Expect a          *
    *   replacement module to appear later.                           *
    *******************************************************************
    
    
    "Style" is the information used by widgets to determine what
    colors, fonts, and other cosmetic values to use when drawing or
    displaying themselves. Similarly to the CSS styling language, each
    widget can have its own style, but when it does not, it inherits
    from a base.
    
    This module provides a class called `Style`, which is a subclass of
    Python's built-in `dict` type. It works like a normal dict,
    except that whenever a value is requested that does not exist in
    the Style, an "inherited" value is returned rather than raising a
    KeyError. The inherited values come from a class attribute of the
    Style class, `Style.base`, which is itself a Style object. The
    `.base` attribute of Style objects can be set to give a style its
    own unique base rather than use the common base.
    
    Measures are taken by the Style class to prevent
    endless recursion when inheriting styles from the base--when a
    Style detects that it is its own base, a KeyError will be raised to
    prevent further recursion. This will not protect from more complex
    inheritence loops, however, so care must be taken to avoid cyclic
    bases or else a RecursionError will almost certainly occur.
    
    After `sbak.widget.init()` is called for the first time,
    `Style.base` is set to a Style object that is based on
    `sbak.widget.DEFUALT_STYLE`, which contains a dict with some
    reasonable default style values. This includes a font from the OS,
    which will be one of the fonts named by `sbak.widget.FONT_NAMES`
    and of the size given by `sbak.widget.FONT_SIZE`. (Fonts are
    measured in _pixels_, not points.)

    `sbak.widget.style.init()` must be called before using anything
    else in this module. This is done automatically by
    `sbak.widget.init()`.
    
    ~~~ Style Keys ~~~
    
    The following style keys are recognized by widgets, and must exist
    and be set to the right value types within the common style:
    
    font:
        
        Font used to draw/display text.**

    
    font-aa:
    
        Whether or not to use font antialiasing when drawing text.
    
    
    text-color:
    
        Color of all text.*
    
    
    widget-color:
    
        Background color of widgets that do not use any of the other
        colors.*
    
    
    widget-alt-color:
    
        Alternate color used by widgets in certain situations.*
        
    
    border-color:
    
        Color of widget borders.*
    
        
    title-color:
    
        Color of the titlebar's background for TitleWindows.*
    
    
    title-text-color:
    
        Color of the titleba's text for TitleWindows.*
        
    
    title-height:
    
        Height of the titlebar in pixels.
    
    
    title-text-pos:
    
        Position of text within the titlebar as an (int,int) pair.
    
    
    desktop-color:
    
        Background color of the desktop.*
    
    -- Notes --
    
    * All colors in a style are processed with `sbak.draw.fix_color`
      before being assigned to the style. This automatically
      includes any style ending in "-color".
    
    ** All fonts in a style must be valid `pygame.font.Font` objects.
    
    ~~~ Default Colors ~~~
    
    Style objects have special behavior for when a color is requested
    that does not exist in the style or in any of its bases: Whenever
    a style key ending in "-color" is requested, and the key does not
    exist in the style or its bases, the value of the style for the key
    "widget-color" is returned.
    
    This mechanism only exists to prevent applications that use custom
    style colors from failing when a style is used that does not
    provide those colors. It is not to be relied, upon, however, and
    as such, a warning will be raised whenever the mechanism is invoked.
    
    ~~~ Default Drawing Methods ~~~
    
    Similar to default colors values, styles provide default drawing
    methods. Whenever a request is made for an attribute beginning with
    the prefix "draw_" and no method of that name is found, the method
    `draw_widget` is used instead, and a warning is raised.
    
    It is generally assumed that all drawing methods of a style will
    conform to the following signature:
    
    def draw_<OBJECT>( self, dest = None, region = None,
                        text = None, bgcolor = None, fgcolor = None)
        return <AFFECTED_REGION>
    
    <OBJCECT>:  A word that describes the object being drawn.
    
    dest:       Surface onto which the object is drawn. If None, the
                screen is used.
    
    region:     The region that the object drawn is to cover. This
                should be a Rect or Rect-like object.
    
    text:       If the widget has any text directly visible on it, this
                is where it is indicated. This only includes text on
                the widget itself, not text of child widgets.
                (In the future, this argument may support more complex
                static obejcts, such as images.)
    
    bgcolor:    Main color of the object. If None, the default color for
                the object is used.
    
    fgcolor:    Color of the text.
    
    <AFFECTED_REGION>:
                a Rect or Rect-like object that indicates where on the
                surface was drawn to. This is usually the same value as
                `region`.

"""

from warnings import warn

from pygame import (
    Rect,
)

from sbak import draw
from sbak.draw import (
    rect as draw_rect,
    rect_ as draw_rect_,
    text as draw_text,
    fix_color
)

__all__ = (
    'DEFAULT_BASE_STYLE',
    
    'Style',
)

# Default common style used by the Style class as a dict.
# (The colors come from a GNOME/Metacity theme called "Glossy".)
DEFAULT_BASE_STYLE = {
    'font' : None,  # Cannot be set until `init` is called.
    'font-aa' : True,
    'text-color' : fix_color(0,0,0),
    'widget-color' : fix_color(237,233,227),
    'widget-alt-color' : fix_color(255,255,255),
    'border-color' : fix_color(0,0,0),
    'title-color' : fix_color(87,154,216),
    'title-text-color' : fix_color(255,255,255),
    'title-height' : 24,
    'title-text-pos' : (16,2),
    'desktop-color' : fix_color(128,128,128),
}

_init = False
def init():
    """ Initializes the style module.
    
        Must be called before using styles. Safe to call multiple
        times; repeated calls are ignored.
        
        Called automatically by `sbak.widget.init`.
    
        Calling this implies a call to `sbak.draw.init()`.
    
        This function is NOT included when the module is imported via
        `from sbak.widget.style import *`.
    """
    global _init
    if not _init:
        draw.init()    
        DEFAULT_BASE_STYLE['font'] = draw.default_font
        Style.base = Style(DEFAULT_BASE_STYLE)
        _init = True

class Style(dict):
    """ Specialized dict for use as the style of widgets.
    
        Works the same way as an ordinary dict, except that
        whenever an attempt is made to get a value that does
        not exist in the Style, the request is deferred to the
        dict in the class attribute `Style.base`. Only if the
        value does not exist in that dict will a KeyError actually
        occur.
        
        See the documentation for the `sbak.widget.style` module for
        more information about styling.
        
        ~~~ Class Attributes ~~~
    
        base:       A Style of common values used by all Style objects
                    whenever they don't have a value requested.
    
    """
    
    __slots__ = ['base']
    
    # Must be set by sbak.widget.init()
    base = None
    
    def __getitem__(self, key):
        try:
            return super(Style,self).__getitem__(self, key)
        except KeyError:
            try:
                if self is not self.base:
                    return self.base[key]
                else:
                    raise KeyError("'%s' could not be found in the style or "
                                   "any of its bases." % key)
            except KeyError:
                if key.endswith("-color") and key != "widget-color":
                    warn("Attempt to access style color '%s' not found in the "
                         "style or its bases." % key)
                    return self["widget-color"]
                else:
                    raise
    
    def __setitem__(self, key, value):
        if key.endswith('-color'):
            value = fix_color(value)
        super(Style,self).__setitem__(key, value)
    
    def __getattr__(self, attr):
        if attr.startswith('draw_'):
            warn("Attempt to access drawing method '%s' not found in the"
                 "style." % attr)
            return self.draw_widget
        else:
            AttributeError(attr)
            
    def draw_widget(self, dest, region, text=None, bgcolor=None,
                    fgcolor=None):
        """ Draws a simple widget box using the style.
        
            dest:       Surface onto which the box should be drawn.
            
            region:     The region of the surface covered by the box.
            
            text:       Currently unused.
            
            bgcolor:    Color of the box. If unspecified, the value of
                        the key "widget-color" is used.
            
            fgcolor:    Currently unused.
            
            This is the most basic drawing function provided by Style.
            If a function beginning with "draw_" is called and that
            method does not exist on the style, then this method will
            be used instead.
        """
        if bgcolor is None:
            bgcolor = self['widget-color']
        region = Rect(region)
        draw_rect(dest, bgcolor, region.inflate(-2,-2))
        draw_rect(dest, self['border-color'], region, 1)
        return region
    
    def draw_text(self, dest, region, text=None, bgcolor=None,
                  fgcolor=None):
        """ Draws generic text with the style's values.
        
            dest:       Destination surface. If None, the screen
                        surface is used.
            
            region:     Region in which to draw the text. Currently
                        only the position is used; the size is ignored.
            
            text:       The text to draw.
            
            bgcolor:    Background of text. If none is given, the
            
            fgcolor:    Color of the text. If None, the value of
                        the key "text-color" will be used.
        
            The values of the "font", "font-aa", "widget-color",
            and "text-color" style keys are used to determine settings
            for drawing text.
            
            Text is SINGLE-LINE ONLY. Newlines will appear as the
            "unknown" character.
            
            Returns the region on the surface that was affected.
            
            TODO: Allow for multiline text.
            TODO: Allow for the use of region for background.
        """
        if text is None:
            text = ""
        if fgcolor is None:
            fgcolor = self['text-color']
        affected = draw_text(dest, region[:2], text, self['font'], fgcolor,
                             bgcolor, self['font-aa'])
        return affected
    
    def draw_titlebar(self, dest=None, region=None, text=None, bgcolor=None,
                        fgcoolor=None):
        """ Draws a titlebar for a form.
        
            dest:       Surface onto which the titlebar is to be drawn.
                        If None, the screen surface is assumed.
        
            region:     The region of the surface that the titlebar
                        should cover. This is NOT just the region of
                        the text, but the whole titlebar. If None is
                        given, the whole surface is assumed.
        
            text:       The caption of the titlebar. If None is given,
                        no caption is drawn.
            
            bgcolor:    The color of the titlebar's fill. If None is
                        given, the value of the key "title-color" is
                        used.
            
            fgcolor:    The color of the caption. If None is given, the
                        value of the key "title-text-color" is used.
            
            A titlebar looks like a box with a border that has some
            text inside. The color of the border is determined by the
            value of the "border-color" key. The font used to draw the
            text is determined by the value of the "font" key.
        """
        if bgcolor is None:
            bgcolor = self['title-color']
        if rect is None:
            if 
        draw_rect(dest, bgcolor, region)
        draw_rect(dest, self['border-color'], region, 1)
        
        textpos = tregion.move(self['title-text-pos']).topleft
        self.draw_text(dest, textpos, self['title-text-color'], None, text, *unused, **kwunused)
    
        
